package com.market.plus.core.domain;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.TableGenerator;

import com.ocm.common.util.DateUtil;
import com.market.plus.core.util.MarketUtil;

@Entity
@Table(name = "PARTICIPANT")
@NamedQueries( { 
   @NamedQuery(name = Participant.FIND_ALL, query = "SELECT participant FROM Participant participant"),
   @NamedQuery(name = Participant.FIND_USERNAME, query = "SELECT participant FROM Participant participant where LOWER(participant.userInfo.username)=LOWER(:username)"),
   @NamedQuery(name = Participant.FIND_GUID, query = "SELECT participant FROM Participant participant where participant.guid=:participantGUID"),
   @NamedQuery(name = Participant.FIND_WAITINGFRIENDS, query = "SELECT participant FROM Participant participant join participant.friends friend where friend.friendInfo.id=:id and friend.lockStatus=:lockStatus")})
public class Participant implements Persistable, ModifyedInfo, StatusInfo {

   public static final String FIND_SQL_NOTFRIENDS = "SELECT p1.* FROM participant p1 " +
         "LEFT JOIN (SELECT f.participant_id as f_id, f.friend_part_id f_f_id FROM participant p " +
         "INNER JOIN friend f ON p.participant_id = f.participant_id OR p.participant_id = f.friend_part_id WHERE p.participant_id = :id) p2 " +
         "ON p1.participant_id = p2.f_id or p1.participant_id = p2.f_f_id WHERE p1.participant_id <> :id and p2.f_f_id is null and p2.f_id is null";

   public static final String FIND_SQL_FRIENDS = "SELECT p1.* FROM participant p1 " +
         "INNER JOIN (SELECT f.participant_id as f_id, f.friend_part_id f_f_id FROM participant p " +
         "INNER JOIN friend f ON (p.participant_id = f.participant_id AND f.lockstatus=:lockStatus1) OR (p.participant_id = f.friend_part_id AND f.lockstatus=:lockStatus2) WHERE p.participant_id = :id) p2 " +
         "ON p1.participant_id = p2.f_id or p1.participant_id = p2.f_f_id WHERE p1.participant_id <> :id";

   public static final String FIND_SQL_EXT_FRIENDS = "SELECT p1.* FROM participant p1 " +
         "INNER JOIN (SELECT f.participant_id as f_id, f.friend_part_id f_f_id FROM participant p " +
         "INNER JOIN friend f ON (p.participant_id = f.participant_id AND f.lockstatus=:lockStatus1) OR (p.participant_id = f.friend_part_id AND f.lockstatus=:lockStatus2) WHERE p.participant_id = :id) p2 " +
         "ON p1.participant_id = p2.f_id or p1.participant_id = p2.f_f_id WHERE p1.participant_id <> :id AND p1.participant_id NOT IN (:ids)";

   public static final String FIND_ALL = "PARTICIPANT.FIND_ALL";

   public static final String FIND_USERNAME = "PARTICIPANT.FIND_USERNAME";

   public static final String FIND_GUID = "PARTICIPANT.FIND_GUID";

   public static final String FIND_WAITINGFRIENDS = "PARTICIPANT.FIND_WAITINGFRIENDS";

   public static final String PARA_ID = "id";

   public static final String PARA_IDs = "ids";

   public static final String PARA_LOCKSTATUS = "lockStatus";
   
   public static final String PARA_LOCKSTATUS1 = "lockStatus1";
   
   public static final String PARA_LOCKSTATUS2 = "lockStatus2";

   public static final String PARA_USERNAME = "username";

   public static final String PARA_GUID = "participantGUID";

   @Id
   @GeneratedValue(strategy = GenerationType.TABLE, generator = "GEN_PARTICIPANT")
   @TableGenerator(name = "GEN_PARTICIPANT", table = "SEQUENCE_LIST", allocationSize = 1, initialValue = 1, pkColumnName = "NAME", valueColumnName = "NEXT_SEQUENCE", pkColumnValue = "PARTICIPANT")
   @Column(name = "PARTICIPANT_ID")
   private Long id;

   @ManyToOne
   @JoinColumn(name = "CITY_ID")
   private City city;

   @Column(name = "FIRST_NAME")
   private String firstName;

   @Column(name = "LAST_NAME")
   private String lastName;

   @Column(name = "NICKNAME")
   private String nickname;

   @Column(name = "ADDRESS")
   private String address;

   @Column(name = "ZIPCODE")
   private String zipcode;

   @Column(name = "PARTICIPANT_GUID")
   private String guid;

   @Column(name = "CREATED_USER")
   private String createdUser;

   @Column(name = "CREATED_DATE")
   private Date createdDate;

   @Column(name = "MODIFYED_USER")
   private String modifyedUser;

   @Column(name = "MODIFYED_DATE")
   private Date modifyedDate;

   @Column(name = "LOGIN_LATEST_DATE")
   private Date loginLastetDate;

   @Column(name = "BLOCKED_DATE")
   private Date blockedDate;

   @Column(name = "status")
   @Enumerated(EnumType.ORDINAL)
   private Status status;

   @OneToOne(cascade=CascadeType.ALL)
   @JoinColumn(name="USER_DETAIL_ID")
   private UserInfo userInfo;

   @OneToOne(cascade=CascadeType.ALL)
   @JoinColumn(name="AVATAR_ID")
   private Avatar avatar;

   @OneToMany(cascade=CascadeType.ALL, mappedBy="participant", orphanRemoval=true)
   private Set<News> news;

   @OneToMany(cascade=CascadeType.ALL, mappedBy="participant", orphanRemoval=true)
   private Set<Album> albums;

   @ManyToMany
   @JoinTable(name = "PARTCIPANT_TRIBE", joinColumns = @JoinColumn(name = "PARTCIPANT_TRIBE_ID", referencedColumnName = "PARTICIPANT_ID"), 
         inverseJoinColumns = @JoinColumn(name = "TRIBE_PARTCIPANT_ID", referencedColumnName = "TRIBE_ID"))
   private Set<Tribe> tribes;

   @OneToMany(cascade=CascadeType.ALL, mappedBy="participant", orphanRemoval=true)
   private Set<Friend> friends;

   @OneToMany(cascade=CascadeType.ALL, mappedBy="friendInfo", orphanRemoval=true)
   private Set<Friend> myfriends;

   @OneToMany(cascade=CascadeType.ALL, mappedBy="participant", orphanRemoval=true)
   private Set<Relationship> relationships;

   @OneToMany(cascade=CascadeType.ALL, mappedBy="participant", orphanRemoval=true)
   private Set<Comment> comments;

   @OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
   @JoinTable(name = "PARTCIPANT_FILES", joinColumns = @JoinColumn(name = "PARTCIPANT_FILES_ID", referencedColumnName = "PARTICIPANT_ID"), 
         inverseJoinColumns = @JoinColumn(name = "FILE_PARTCIPANT_ID", referencedColumnName = "CONTENTFILE_ID"))
   private Set<ContentFile> contentFiles;

   public Participant() {
      tribes = new HashSet<Tribe>();
      contentFiles = new HashSet<ContentFile>();
      news = new HashSet<News>();
      comments = new HashSet<Comment>();
      albums = new HashSet<Album>();
      friends = new HashSet<Friend>();
      myfriends = new HashSet<Friend>();
      relationships = new HashSet<Relationship>();
   }

   public Long getId() {
      return id;
   }

   public void setId(Long id) {
      this.id = id;
   }

   public String getFirstName() {
      return firstName;
   }

   public void setFirstName(String firstName) {
      this.firstName = firstName;
   }

   public String getLastName() {
      return lastName;
   }

   public void setLastName(String lastName) {
      this.lastName = lastName;
   }

   public String getNickname() {
      return nickname;
   }

   public void setNickname(String nickname) {
      this.nickname = nickname;
   }

   public String getAddress() {
      return address;
   }

   public void setAddress(String address) {
      this.address = address;
   }

   public City getCity() {
      return city;
   }

   public void setCity(City city) {
      this.city = city;
   }

   public Date getBlockedDate() {
      return blockedDate;
   }

   public void setBlockedDate(Date blockedDate) {
      this.blockedDate = blockedDate;
   }

   public Status getStatus() {
      return status;
   }

   public void setStatus(Status status) {
      this.status = status;
   }

   public String getCreatedUser() {
      return createdUser;
   }

   public void setCreatedUser(String createdUser) {
      this.createdUser = createdUser;
   }

   public Date getCreatedDate() {
      return createdDate;
   }

   public void setCreatedDate(Date createdDate) {
      this.createdDate = createdDate;
   }

   public String getModifyedUser() {
      return modifyedUser;
   }

   public void setModifyedUser(String modifyedUser) {
      this.modifyedUser = modifyedUser;
   }

   public Date getModifyedDate() {
      return modifyedDate;
   }

   public void setModifyedDate(Date modifyedDate) {
      this.modifyedDate = modifyedDate;
   }

   public Avatar getAvatar() {
      return avatar;
   }

   public void setAvatar(Avatar avatar) {
      this.avatar = avatar;
   }

   public String getZipcode() {
      return zipcode;
   }

   public void setZipcode(String zipcode) {
      this.zipcode = zipcode;
   }

   public String getGuid() {
      return guid;
   }

   public void setGuid(String guid) {
      this.guid = guid;
   }

   public UserInfo getUserInfo() {
      return userInfo;
   }

   public Date getLoginLastetDate() {
	  return loginLastetDate;
   }

   public void setLoginLastetDate(Date loginLastetDate) {
	   this.loginLastetDate = loginLastetDate;
   }

   public void setUserInfo(UserInfo userInfo) {
      this.userInfo = userInfo;
   }

   public List<News> getNews() {
      return new ArrayList<News>(news);
   }

   public void setNews(Set<News> news) {
      this.news.clear();
      this.news.addAll(news);
   }

   @Override
   public boolean equals(Object obj) {
      Participant objectCompare = (Participant) obj;
      if (this.getId().longValue() == objectCompare.getId().longValue()) {
         return true;
      }
      return false;
   }

   public List<Tribe> getTribes() {
      return new ArrayList<Tribe>(this.tribes);
   }

   public void setTribes(List<Tribe> tribes) {
      this.tribes.clear();
      this.tribes.addAll(tribes);
   }

   public List<ContentFile> getContentFiles() {
      return new ArrayList<ContentFile>(contentFiles);
   }

   public void setContentFiles(List<ContentFile> contentFiles) {
      this.contentFiles.clear();
      this.contentFiles.addAll(contentFiles);
   }

   public List<Album> getAlbums() {
      return new ArrayList<Album>(albums);
   }

   public void setAlbums(List<Album> albums) {
      this.albums.clear();
      this.albums.addAll(albums);
   }

   public List<Comment> getComments() {
      return new ArrayList<Comment>(comments);
   }

   public void setComments(List<Comment> comments) {
      this.comments.clear();
      this.comments.addAll(comments);
   }

   public void addContentFile(ContentFile contentFile){
      //contentFile.setParticipant(this);
      this.contentFiles.add(contentFile);
   }

   public void addAlbum(Album album){
      album.setParticipant(this);
      this.albums.add(album);
   }

   public void addTribe(Tribe tribe){
      this.tribes.add(tribe);
   }

/*   public String getFriendIds() {
      return friendIds;
   }

   public void setFriendIds(String friendIds) {
      this.friendIds = friendIds;
   }*/

   public List<Friend> getFriends() {
      List<Friend> friends = new ArrayList<Friend>(this.friends);
      return friends;
   }

   public void setFriends(List<Friend> friends) {
      this.friends.clear();
      this.friends.addAll(friends);
   }

   public List<Friend> getMyFriends() {
      List<Friend> friends = new ArrayList<Friend>(this.myfriends);
      return friends;
   }

   public void setMyFriends(List<Friend> friends) {
      this.myfriends.clear();
      this.myfriends.addAll(friends);
   }

   public void addFriend(Friend friend){
      friend.setParticipant(this);
      this.friends.add(friend);
   }

   public void acceptFriend(Participant myfriend){
      for (Iterator<Friend> it=this.myfriends.iterator(); it.hasNext();){
         Friend friend = it.next();
         if (myfriend.equals(friend.getParticipant())){
            MarketUtil.setModifyedUser(friend);
            friend.setAcceptedDate(DateUtil.getCurrentDate());
            friend.setLockStatus(LockStatus.AVAIABLE);
            //myfriend.appendFriendId(this.id);
            //this.appendFriendId(myfriend.getId());
            break;
         }
      }
   }

/*   private void appendFriendId(Long friendId){
      if (this.friendIds == null)
         this.friendIds = this.id.toString();

      String pattern = friendId.toString();
      if (this.friendIds.contains("|"))
         pattern = "|" + friendId;
      
      if (!this.friendIds.contains(pattern)){
         String partipantId = friendId.toString();
         if ("".equals(this.friendIds))
            this.friendIds = partipantId;
         else 
            this.friendIds = this.friendIds + "|" + partipantId;
      }
   }

   private void removeFriendId(Friend friend){
      if (this.friendIds != null){
         String partipantId = friend.getParticipant().getId().toString();
         String pattern = partipantId;
         if (this.friendIds.contains("|"))
            pattern = "|" + partipantId;

         int indexOf = this.friendIds.indexOf(pattern);
         int nextStart = indexOf + pattern.length(); 
         this.friendIds=this.friendIds.substring(0, indexOf).concat(this.friendIds.substring(nextStart));
      }
   }*/

   public void lockFriend(long myfriendId){
      for (Iterator<Friend> it=this.myfriends.iterator(); it.hasNext();){
         Friend friend = it.next();
         if (friend.getParticipant().getId().longValue() == myfriendId){
            MarketUtil.setModifyedUser(friend, Status.UPDATED);
            friend.setLockStatus(LockStatus.LOCKED);
            return;
         }
      }
      for (Iterator<Friend> it=this.friends.iterator(); it.hasNext();){
         Friend friend = it.next();
         if (friend.getFriendInfo().getId().longValue() == myfriendId){
            MarketUtil.setModifyedUser(friend, Status.UPDATED);
            friend.setLockStatus(LockStatus.ISLOCKED);
            return;
         }
      }
   }

   public void unlockFriends(long myfriendId){
      for (Iterator<Friend> it=this.myfriends.iterator(); it.hasNext();){
         Friend friend = it.next();
         if (friend.getParticipant().getId().longValue() == myfriendId){
            MarketUtil.setModifyedUser(friend, Status.UPDATED);
            friend.setLockStatus(LockStatus.AVAIABLE);
            return;
         }
      }
      for (Iterator<Friend> it=this.friends.iterator(); it.hasNext();){
         Friend friend = it.next();
         if (friend.getFriendInfo().getId().longValue() == myfriendId){
            MarketUtil.setModifyedUser(friend, Status.UPDATED);
            friend.setLockStatus(LockStatus.AVAIABLE);
            return;
         }
      }
   }

   public void removeFriends(long[] friendIds){
      List<Friend> removeList = new ArrayList<Friend>();
      for (Iterator<Friend> it=this.myfriends.iterator(); it.hasNext();){
         Friend friend = it.next();
         for (long friendId : friendIds){
            if (friend.getParticipant().getId().longValue() == friendId){
               removeList.add(friend);
               //removeFriendId(friend);
               break;
            }
         }
      }
      if(removeList.size() > 0){
         this.myfriends.removeAll(removeList);
      }
   }

   public void addFriendToRelationship(long relationshipId, long friendId){
      Friend expectedFriend = null;
      for (Iterator<Friend> it=this.myfriends.iterator(); it.hasNext();){
         Friend friend = it.next();
         if (friend.getParticipant().getId().longValue() == friendId){
            expectedFriend = friend;
            break;
         }
      }
      if (expectedFriend != null){
         for (Iterator<Relationship> it=this.relationships.iterator(); it.hasNext();){
            Relationship relationship = it.next();
            if (relationship.getId().longValue() == relationshipId){
               relationship.addFriend(expectedFriend);
               break;
            }
         }
      }
   }
   
   public void removeFriendFromRelationship(long relationshipId, long friendId){
      Friend expectedFriend = null;
      for (Iterator<Friend> it=this.myfriends.iterator(); it.hasNext();){
         Friend friend = it.next();
         if (friend.getParticipant().getId().longValue() == friendId){
            expectedFriend = friend;
            break;
         }
      }
      if (expectedFriend != null){
         for (Iterator<Relationship> it=this.relationships.iterator(); it.hasNext();){
            Relationship relationship = it.next();
            if (relationship.getId().longValue() == relationshipId){
               relationship.removeFriend(expectedFriend);
               break;
            }
         }
      }
   }

   public List<Relationship> getRelationships() {
      List<Relationship> relationships = new ArrayList<Relationship>(this.relationships);
      return relationships;
   }

   public void setRelationships(List<Relationship> relationships) {
      this.relationships.clear();
      this.relationships.addAll(relationships);
   }
   
   public void addRelationship(Relationship relationship){
      relationship.setParticipant(this);
      this.relationships.add(relationship);
   }

   public Relationship getRelationship(String relationName){
      for (Iterator<Relationship> it=this.relationships.iterator(); it.hasNext();){
         Relationship relationship = it.next();
         if (relationName.equals(relationship.getRelationName())){
            return relationship;
         }
      }
      return null;
   }

   public void removeRelationship(long relationId){
      for (Iterator<Relationship> it=this.relationships.iterator(); it.hasNext();){
         Relationship relationship = it.next();
         if (relationship.getId().longValue() == relationId){
            this.relationships.remove(relationship);
            break;
         }
      }
   }
}
